#ifndef __ZHONG_CHANNEL__
#define __ZHONG_CHANNEL__

#include <brpc/channel.h>
#include <mutex>
#include <vector>
#include <unordered_map>
#include "logger.hpp"
// namespace zhong
// {
//     // 提供服务的管理
//     namespace servicer
//     {

//     }
// }
namespace bite_im
{
    using ChannelPtr = std::shared_ptr<brpc::Channel>;
    // 建立服务于信道的映射关系
    class ServiceChannel
    {
    public:
        using ptr = std::shared_ptr<ServiceChannel>;
        ServiceChannel(const std::string &service_name) : _service_name(service_name), _rr_seq(0) {}
        // 服务上线一个节点，append新增信道
        void append(const std::string &host_address)
        {
            auto channel = std::make_shared<brpc::Channel>();
            auto options = std::make_shared<brpc::ChannelOptions>();
            options->timeout_ms = -1; // 连接空闲超时时间
            options->connect_timeout_ms = -1;
            options->max_retry = 3;
            options->protocol = "baidu_std"; // 序列化协议为baidu_std
            // 连接服务器
            int ret = channel->Init(host_address.c_str(), options.get());
            if (ret == -1)
            {
                LOG_ERROR("初始化{}-{}信道失败", _service_name, host_address);
                return;
            }
            // 对类内结构进行操作
            std::unique_lock<std::mutex> _lock(_mutex);
            _hosts.insert(std::make_pair(_service_name, channel));
            _channels.push_back(channel);
        }
        // 服务下线一个节点，remove删除信道
        void remove(const std::string &host_address)
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            auto it = _hosts.find(host_address);
            if (it == _hosts.end())
            {
                LOG_WARN("{}-{}服务删除节点时，没有节点对应的信道信息", _service_name, host_address);
                return;
            }
            // 删除在vecotr中的对象
            for (auto del = _channels.begin(); del != _channels.end(); ++del)
            {
                if (*del == it->second)
                {
                    _channels.erase(del);
                    break;
                }
            }
            // 删除映射
            _hosts.erase(it);
        }
        // 基于rr轮转，获取一个信道来提供服务
        ChannelPtr choose()
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            if (_channels.size() == 0)
            {
                return ChannelPtr();
            }
            int index = _rr_seq++ % _channels.size();
            return _channels[index];
        }
        void clear()
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _channels.clear();
            _hosts.clear();
        }

    private:
        std::mutex _mutex;
        int32_t _rr_seq;                                    // rr轮转
        std::string _service_name;                          // 服务名称
        std::vector<ChannelPtr> _channels;                  // 提供某个服务的信道集合
        std::unordered_map<std::string, ChannelPtr> _hosts; // 主机地址和信道的映射关系
    };

    class ServiceManager
    {
    public:
        using ptr = std::shared_ptr<ServiceManager>;
        ServiceManager() {}
        // 获取信道对象进行服务
        ChannelPtr choose(const std::string &service_name)
        {
            ServiceChannel::ptr service;
            {
                std::unique_lock<std::mutex> _lock(_mutex);
                auto it = _services.find(service_name);
                if (it == _services.end())
                {
                    LOG_WARN("{}服务选择节点时，没有服务信息", service_name);
                    return ChannelPtr();
                }
                service = it->second;
            }

            return service->choose();
        }
        // 声明关心和管理的服务
        void declareService(const std::string &service_name)
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            if (_follow_services.count(service_name) == 1)
            {
                LOG_INFO("服务{}已存在，无需重复添加", service_name);
                return;
            }
            _follow_services.insert(service_name);
        }
        // 删除服务
        void deleteService(const std::string &service_name)
        {
            ServiceChannel::ptr service;
            {
                std::unique_lock<std::mutex> _lock(_mutex);
                if (_follow_services.count(service_name) == 0)
                {
                    LOG_INFO("服务{}不存在，删除错误", service_name);
                    return;
                }
                // 删除对该服务的关系、心和删除映射关系
                _follow_services.erase(service_name);
                service = _services[service_name];
                _services.erase(service_name);
            }
            // 清理掉服务
            service->clear();
        }
        // 服务上线的回调函数 --- 本质上为了增加某个服务的信道、增加节点
        void onServiceOnline(const std::string &service_instance, const std::string &host_address)
        {
            // 我们上线一个服务，都是上线一个服务样例，需要获取实际的服务名
            std::string service_name = getServiceName(service_instance);
            ServiceChannel::ptr service;
            {
                std::unique_lock<std::mutex> _lock(_mutex);
                // 是否关心这个服务
                if (_follow_services.count(service_name) == 0)
                {
                    LOG_DEBUG("{}服务上线时，并不关心该服务", service_name);
                    return;
                }
                auto it = _services.find(service_name);
                // 服务被关心了，但是还没有上线
                if (it == _services.end())
                {
                    LOG_WARN("{}服务上线时，没有服务信息", service_name);
                    service = std::make_shared<ServiceChannel>(service_name);
                    _services.insert(std::make_pair(service_name, service));
                }
                // 服务已经上线了
                else
                {
                    service = it->second;
                }
            }
            service->append(host_address);
            LOG_DEBUG("{}-{}服务上线新节点", service_name, host_address);
        }
        // 服务下线的回调函数
        void onServiceOffLine(const std::string &service_name, const std::string &host_address)
        {
            ServiceChannel::ptr service;
            {
                std::unique_lock<std::mutex> _lock(_mutex);
                if (_follow_services.count(service_name) == 0)
                {
                    LOG_DEBUG("{}服务下线时，并不关心该服务", service_name);
                    return;
                }
                auto it = _services.find(service_name);
                if (it == _services.end())
                {
                    LOG_WARN("{}服务下线时，没有服务信息", service_name);
                    return;
                }
                service = it->second;
            }
            service->remove(host_address);
        }

    private:
        std::string getServiceName(const std::string &service_instance)
        {
            auto pos = service_instance.find_last_of('/');
            // pos找不到返回自己，找到了截断一下
            return pos == std::string::npos ? service_instance : service_instance.substr(0, pos);
        }

    private:
        std::mutex _mutex;
        std::unordered_set<std::string> _follow_services;
        std::unordered_map<std::string, ServiceChannel::ptr> _services;
    };
}
#endif